/////////////////////////////////////////////////////////////////////////////
//
// (c) 2007 BinaryComponents Ltd.  All Rights Reserved.
//
// http://www.binarycomponents.com/
//
/////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections;
using System.Windows.Forms;
using SuperListEx.Utility.Collections;
using System.Collections.Generic;

namespace SuperListEx.ItemLists
{
    /// <summary>
    /// Base class for implementing list storage mechanism
    /// </summary>
    public abstract class ItemList
    {
        #region vars
        private ProcessingStyle _processingStyle = ProcessingStyle.OnIdle;
        private IComparer _objectComparer = null;
        private Column[] _groupColumns;
        private ListControl _listControl;
        #endregion

        #region abstact properties
        /// <summary>
        /// Returns the count of items this list holds.
        /// </summary>
        public abstract int Count
        {
            get;
        }

        /// <summary>
        /// Returns the the item at <paramref name="index"/>
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public abstract object this[int index]
        {
            get;
        }
        #endregion

        #region internal properties
        /// <summary>
        /// Represents the grouping used when the list was created.
        /// </summary>
        internal Column[] GroupColumns
        {
            get
            {
                return _groupColumns;
            }
            set
            {
                _groupColumns = value;
            }
        }
        #endregion

        #region public abstract
        public abstract void Add(object item);
        public abstract void AddRange(IEnumerable items);
        public abstract void Remove(object item);
        public abstract void RemoveRange(IEnumerable items);
        public abstract void Clear();
        public abstract List<object> ToList();
        public abstract void ItemsChanged(params object[] items);
        public abstract int IndexOf(object o);
        public abstract void Sort();
        #endregion

        #region public properties
        /// <summary>
        /// The must not return the same same sort order for any given two items otherwise otherwise after sorting 
        /// items can jump around as dotnet sort doesn't guarentee original order placement where items have the 
        /// same sort order value.
        /// </summary>
        public IComparer ObjectComparer
        {
            get
            {
                return _objectComparer;
            }
            set
            {
                _objectComparer = value;
            }
        }
        #endregion

        #region protected functions
        /// <summary>
        /// Returns the attached list control.
        /// </summary>
        protected internal ListControl ListControl
        {
            get
            {
                return _listControl;
            }
            set
            {
                if (_listControl != value)
                {
                    if (_listControl != null)
                    {
                        _listControl.Columns.DataChanged -= Columns_DataChanged;
                        DetachFromColumnsEvents(_listControl.Columns.ToArray());
                    }
                    _listControl = value;
                    if (_listControl != null)
                    {
                        _listControl.Columns.DataChanged += Columns_DataChanged;
                        AttachToColumnsEvents(_listControl.Columns.ToArray());
                    }
                }
            }
        }
        #endregion

        #region private functions
        private void Columns_DataChanged(object sender, EventInfo<Column> e)
        {
            switch (e.EventType)
            {
                case EventType.Deleted:
                    DetachFromColumnsEvents(e.Items);
                    break;
                case EventType.Added:
                    AttachToColumnsEvents(e.Items);
                    break;
            }
        }

        private void AttachToColumnsEvents(IEnumerable<Column> columns)
        {
            foreach (Column column in columns)
            {
                column.DataChanged += column_DataChanged;
            }
        }

        private void DetachFromColumnsEvents(IEnumerable<Column> columns)
        {
            foreach (Column column in columns)
            {
                column.DataChanged -= column_DataChanged;
            }
        }

        private void column_DataChanged(object sender, ColumnDataChangedEventArgs e)
        {
            switch (e.WhatChanged)
            {
                case WhatPropertyChanged.IsGroup:
                    Sort();
                    break;
                case WhatPropertyChanged.IsVisible:
                    if (e.Column.SortOrder != SortOrder.None)
                    {
                        Sort();
                    }
                    break;
                case WhatPropertyChanged.SortOrder:
                    Sort();
                    break;
            }
        }


        #endregion
    }
}